﻿using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Markup;
using RSSFeedReader.Controls;
using RSSFeedReader.Data.Models;
using RSSFeedReader.Services;
using RSSFeedReader.ViewModels;
using RSSFeedReader.Views;
using SingleInstanceApplication;

namespace RSSFeedReader
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class RSSFeedReaderApplication : System.Windows.Application,
        IDisplayMessageService,
        IDisplayWindowService,
        ILoggerService
    {
        #region Members

        private AddNewFeedView _addNewFeedView;
        private AddNewFeedViewModel _addNewFeedViewModel;
        private AddNewFolderView _addNewFolderView;
        private AddNewFolderViewModel _addNewFolderViewModel;
        private ChannelPropertiesView _channelPropertiesView;
        private ChannelPropertiesViewModel _channelPropertiesViewModel;
        private MoveToFolderView _moveToFolderView;
        private MoveToFolderViewModel _moveToFolderViewModel;
        private ManageFeedsView _manageFeedsView;
        private ManageFeedsViewModel _manageFeedsViewModel;
        private RenameChannelView _renameChannelView;
        private RenameChannelViewModel _renameChannelViewModel;

        /// <summary>
        /// Constant string for add new feed.
        /// </summary>
        public const string ADD_NEW_FEED_COMMAND ="AddNewFeed";


        #endregion

        #region Private Properties

        private MainViewModel MainVM { get; set; }

        #endregion

        #region Events

        /// <summary>
        /// Occurs when a Dragdrop operation is complete.
        /// </summary>
        public event EventHandler<MyTreeViewDragEventArgs> DragDropCompleted;

        #endregion

        #region Override Methods

        /// <summary>
        /// Override OnStartUp to set the culture info.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnStartup(StartupEventArgs e)
        {
            // register single instance app. and check for existence of other process
            if (!ApplicationInstanceManager.CreateSingleInstance(
                    Assembly.GetExecutingAssembly().GetName().Name,
                    SingleInstanceCallback)) return; // exit, if same app. is running

            // *******************************************************************
            // TODO - Uncomment one of the lines of code that create a CultureInfo
            // in order to see the application run with localized text in the UI.
            // *******************************************************************

            CultureInfo culture = null;

            // ITALIAN
            //culture = new CultureInfo("it-IT");


            // FRENCH
            //culture = new CultureInfo("fr-CH");


            // GERMAN
            //culture = new CultureInfo("de-DE");

            if (culture != null)
            {
                Thread.CurrentThread.CurrentCulture = culture;
                Thread.CurrentThread.CurrentUICulture = culture;
            }

            // Ensure the current culture passed into bindings is the OS culture.
            // By default, WPF uses en-US as the culture, regardless of the system settings.
            FrameworkElement.LanguageProperty.OverrideMetadata(
              typeof(FrameworkElement),
              new FrameworkPropertyMetadata(
                  XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

            // Create the ViewModel and expose it using the View's DataContext
            MainView view = new MainView();
            MainWindow = view;
            MainViewModel mainViewModel = new MainViewModel();
            mainViewModel.RequestClose += new EventHandler(OnMainViewModelRequestClose);
            MainVM = mainViewModel;
            ChannelView channelView = view.FindName("_ChannelView") as ChannelView;
            channelView.DragDropCompleted += new EventHandler<MyTreeViewDragEventArgs>(OnChannelDragDropCompleted);
            view.DataContext = mainViewModel;
            view.Show();

            // If being loaded from firefox for example to subscribe to a feed.
            ProcessCommandLineArgs(e.Args);

            base.OnStartup(e);
        }

        /// <summary>
        /// Event handler for when the RSSFeedReaderApplication is shutting down.
        /// </summary>
        /// <param name="e">Event arguments describing the event.</param>
        protected override void OnExit(ExitEventArgs e)
        {
            ChannelDataSource.Instance.Save();
            MainVM.Dispose();
            base.OnExit(e);
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Event handler for when the <see cref="RSSFeedReader.ViewModels.MainViewModel"/>
        /// requests to be closed.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">Event arguments describing the event.</param>
        void OnMainViewModelRequestClose(object sender, EventArgs e)
        {
            System.Windows.Application.Current.Shutdown();
        }

        /// <summary>
        /// Event handler for when a channel is moved.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">Event arguments describing the event.</param>
        void OnChannelDragDropCompleted(object sender, MyTreeViewDragEventArgs e)
        {
            if (DragDropCompleted != null)
            {
                DragDropCompleted(sender, e);
            }
        }

        private void ProcessCommandLineArgs(string[] args)
        {
            if (args.Length < 1) return;

            foreach (string arg in args)
            {
                if (arg.Equals(RSSFeedReaderApplication.ADD_NEW_FEED_COMMAND))
                {
                    ShowAddNewFeedView();
                }
                else if (arg.Contains("feed:"))
                {
                    string feed = arg.Replace("feed:", "http:");

                    if (!ChannelDataSource.Instance.ContainsChannel(feed))
                        ChannelDataSource.Instance.AddChannel(feed);
                }
            }
        }

        /// <summary>
        /// Single instance callback handler.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="SingleInstanceApplication.InstanceCallbackEventArgs"/> instance containing the event data.</param>
        private void SingleInstanceCallback(object sender, InstanceCallbackEventArgs args)
        {
            if (args == null || Dispatcher == null) return;
            Action<bool> d = (bool x) =>
            {
                ProcessCommandLineArgs(args.CommandLineArgs);
            };
            Dispatcher.Invoke(d, true);
        }

        #endregion

        #region IDisplayMessageService Members

        /// <summary>
        /// Displays a message box with specified text, caption, buttons, and icon.
        /// </summary>
        /// <param name="message">The text to display in the message box.</param>
        /// <param name="caption">The text to display in the title bar of the message box.</param>
        /// <param name="buttons">One of the System.Windows.Forms.MessageBoxButtons values that specifies which
        /// buttons to display in the message box.</param>
        /// <param name="icon">One of the System.Windows.Forms.MessageBoxIcon values that specifies which
        /// icon to display in the message box.</param>
        /// <returns>One of the System.Windows.Forms.DialogResult values.</returns>
        public System.Windows.Forms.DialogResult ShowMessage(
            string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon)
        {
            return System.Windows.Forms.MessageBox.Show(message, caption, buttons, icon);
        }

        /// <summary>
        /// Displays an open file dialoge, with the specified title and filter.
        /// </summary>
        /// <param name="title">The file dialog box title.</param>
        /// <param name="filter">The file filtering options available in the dialog box.</param>
        /// <param name="fileName">The file name selected in the file dialog box.</param>
        /// <returns>One of the System.Windows.Forms.DialogResult values.</returns>
        public System.Windows.Forms.DialogResult OpenFileDialog(
            string title, string filter, out string fileName)
        {
            System.Windows.Forms.DialogResult dialogResult;
            fileName = string.Empty;
            System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
            ofd.Title = title;
            ofd.Filter = filter;
            dialogResult = ofd.ShowDialog();
            fileName = ofd.FileName;
            return dialogResult;
        }

        /// <summary>
        /// Displays a save file dialoge, with the specified title and filter.
        /// </summary>
        /// <param name="title">The file dialog box title.</param>
        /// <param name="filter">The file filtering options available in the dialog box.</param>
        /// <param name="fileName">The file name selected in the file dialog box.</param>
        /// <returns>One of the System.Windows.Forms.DialogResult values.</returns>
        public System.Windows.Forms.DialogResult SaveFileDialog(
            string title, string filter, out string fileName)
        {
            System.Windows.Forms.DialogResult dialogResult;
            fileName = string.Empty;
            System.Windows.Forms.SaveFileDialog sfd = new System.Windows.Forms.SaveFileDialog();
            sfd.Title = title;
            sfd.Filter = filter;
            dialogResult = sfd.ShowDialog();
            fileName = sfd.FileName;
            return dialogResult;
        }

        #endregion

        #region ILoggerService Members

        /// <summary>
        /// Logs to the event log using the params provided.
        /// </summary>
        /// <param name="type">The type of logging.</param>
        /// <param name="message">The actual message string to be logged.</param>
        public void LogMessage(string type, string message)
        {
            string logFile = "Log.txt";
            string logDirectory = Path.Combine(ChannelDataSource.Instance.ApplicationDataLocation, "Log");
            string dateTime = DateTime.Now.ToString();

            if (!Directory.Exists(logDirectory))
            {
                Directory.CreateDirectory(logDirectory);
            }

            message = string.Format("{0}\t{1}\t{2}", dateTime, type, message);

            using (TextWriter tx = File.AppendText(Path.Combine(logDirectory, logFile)))
            {
                tx.WriteLine(message);
            }
        }

        #endregion

        #region IDisplayWindowService Members

        /// <summary>
        /// Displays the Add New Feed dialogue.
        /// </summary>
        public void ShowAddNewFeedView()
        {
            _addNewFeedView = new AddNewFeedView();
            _addNewFeedViewModel = new AddNewFeedViewModel();
            _addNewFeedViewModel.RequestClose += new EventHandler(OnAddNewFeedRequestClose);
            _addNewFeedView.DataContext = _addNewFeedViewModel;
            _addNewFeedView.ShowDialog();
        }

        /// <summary>
        /// Event handler for when the <see cref="RSSFeedReader.ViewModels.AddNewFeedViewModel"/>
        /// requests to be closed.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">Event arguments describing the event.</param>
        void OnAddNewFeedRequestClose(object sender, EventArgs e)
        {
            _addNewFeedViewModel.Dispose();
            _addNewFeedView.Close();
        }

        /// <summary>
        /// Displays the Add New Folder dialogue.
        /// </summary>
        public void ShowAddNewFolderView()
        {
            _addNewFolderView = new AddNewFolderView();
            _addNewFolderViewModel = new AddNewFolderViewModel();
            _addNewFolderViewModel.RequestClose += new EventHandler(OnAddNewFolderRequestClose);
            _addNewFolderView.DataContext = _addNewFolderViewModel;
            _addNewFolderView.ShowDialog();
        }

        /// <summary>
        /// Displays the Add New Folder dialogue.
        /// </summary>
        /// <param name="channel">The Channel to add the folder to</param>
        public void ShowAddNewFolderView(Channel channel)
        {
            _addNewFolderView = new AddNewFolderView();
            _addNewFolderViewModel = new AddNewFolderViewModel(channel);
            _addNewFolderViewModel.RequestClose += new EventHandler(OnAddNewFolderRequestClose);
            _addNewFolderView.DataContext = _addNewFolderViewModel;
            _addNewFolderView.ShowDialog();
        }

        /// <summary>
        /// Event handler for when the <see cref="RSSFeedReader.ViewModels.AddNewFolderViewModel"/>
        /// requests to be closed.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">Event arguments describing the event.</param>
        void OnAddNewFolderRequestClose(object sender, EventArgs e)
        {
            _addNewFolderViewModel.Dispose();
            _addNewFolderView.Close();
        }

        /// <summary>
        /// Displays the Manage Feeds dialogue.
        /// </summary>
        public void ShowManageFeedsView()
        {
            _manageFeedsView = new ManageFeedsView();
            _manageFeedsView.DragDropCompleted += new EventHandler<MyTreeViewDragEventArgs>(OnChannelDragDropCompleted);
            _manageFeedsViewModel = new ManageFeedsViewModel();
            _manageFeedsViewModel.RequestClose += new EventHandler(OnManageFeedsViewModelRequestClose);
            _manageFeedsView.DataContext = _manageFeedsViewModel;
            _manageFeedsView.ShowDialog();
        }

        /// <summary>
        /// Event handler for when the <see cref="RSSFeedReader.ViewModels.ManageFeedsViewModel"/>
        /// requests to be closed.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">Event arguments describing the event.</param>
        void OnManageFeedsViewModelRequestClose(object sender, EventArgs e)
        {
            if (_manageFeedsViewModel.SaveChanges)
            {
                MainVM.Timer.Interval = TimeSpan.FromMinutes(_manageFeedsViewModel.RefreshPeriod);
            }
            _manageFeedsViewModel.Dispose();
            _manageFeedsView.Close();
        }

        /// <summary>
        /// Displays the Move to Folder dialogue.
        /// </summary>
        /// <param name="channelViewModel">The Channel to move.</param>
        public void ShowMoveToFolderView(ChannelViewModel channelViewModel)
        {
            _moveToFolderView = new MoveToFolderView();
            _moveToFolderViewModel = new MoveToFolderViewModel(channelViewModel);
            _moveToFolderViewModel.RequestClose += new EventHandler(OnShowMoveToFolderViewRequestClose);
            _moveToFolderView.DataContext = _moveToFolderViewModel;
            _moveToFolderView.ShowDialog();
        }

        /// <summary>
        /// Event handler for when the <see cref="RSSFeedReader.ViewModels.MoveToFolderViewModel"/>
        /// requests to be closed.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">Event arguments describing the event.</param>
        void OnShowMoveToFolderViewRequestClose(object sender, EventArgs e)
        {
            _moveToFolderViewModel.Dispose();
            _moveToFolderView.Close();
        }

        /// <summary>
        /// Displays the properties of a specified Channel.
        /// </summary>
        /// <param name="channelViewModel">The Channel to show the properties of.</param>
        public void ShowChannelPropertiesView(ChannelViewModel channelViewModel)
        {
            _channelPropertiesView = new ChannelPropertiesView();
            _channelPropertiesViewModel = new ChannelPropertiesViewModel(channelViewModel);
            _channelPropertiesViewModel.RequestClose += new EventHandler(OnChannelPropertiesViewModelRequestClose);
            _channelPropertiesView.DataContext = _channelPropertiesViewModel;
            _channelPropertiesView.ShowDialog();
        }

        /// <summary>
        /// Event handler for when the <see cref="RSSFeedReader.ViewModels.ChannelPropertiesViewModel"/>
        /// requests to be closed.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">Event arguments describing the event.</param>
        void OnChannelPropertiesViewModelRequestClose(object sender, EventArgs e)
        {
            _channelPropertiesViewModel.Dispose();
            _channelPropertiesView.Close();
        }

        /// <summary>
        /// Displayes the Rename Channel dialogue.
        /// </summary>
        /// <param name="channelViewModel">The ChannelViewModel to rename.</param>
        public void ShowRenameChannelView(ChannelViewModel channelViewModel)
        {
            _renameChannelView = new RenameChannelView();
            _renameChannelViewModel = new RenameChannelViewModel(channelViewModel);
            _renameChannelViewModel.RequestClose += new EventHandler(OnRenameChannelViewModelRequestClose);
            _renameChannelView.DataContext = _renameChannelViewModel;
            _renameChannelView.ShowDialog();
        }

        /// <summary>
        /// Event handler for when the <see cref="RSSFeedReader.ViewModels.RenameChannelViewModel"/>
        /// requests to be closed.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">Event arguments describing the event.</param>
        void OnRenameChannelViewModelRequestClose(object sender, EventArgs e)
        {
            _renameChannelViewModel.Dispose();
            _renameChannelView.Close();
        }

        #endregion
    }
}
